package com.sec.android.app.myfiles.facade.cmd;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;

import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.dialog.EditTextDialogFragment;
import com.sec.android.app.myfiles.fragment.AbsMyFilesFragment;
import com.sec.android.app.myfiles.info.AppConstants;
import com.sec.android.app.myfiles.listener.ListenerMgr;
import com.sec.android.app.myfiles.listener.SystemBroadcastReceiver;
import com.sec.android.app.myfiles.listener.SystemBroadcastReceiver.OnMediaUnmounted;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.log.SamsungAnalyticsLog;
import com.sec.android.app.myfiles.module.abstraction.FileRecord;
import com.sec.android.app.myfiles.module.preview.CompressFileRecord;
import com.sec.android.app.myfiles.navigation.NavigationChangedObserver;
import com.sec.android.app.myfiles.navigation.NavigationInfo;
import com.sec.android.app.myfiles.navigation.NavigationManager;
import com.sec.android.app.myfiles.operation.FileOperationArgs;
import com.sec.android.app.myfiles.operation.FileOperationFragment;
import com.sec.android.app.myfiles.operation.FileOperator;
import com.sec.android.app.myfiles.operation.compress.AbsCompressorImp;
import com.sec.android.app.myfiles.util.FileUtils;

import org.puremvc.java.multicore.interfaces.INotification;
import org.puremvc.java.multicore.patterns.command.SimpleCommand;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Locale;

public class DecompressRecordsCmd extends SimpleCommand implements EditTextDialogFragment.EditTextCallback, FileOperationFragment.PostOperation,
        NavigationChangedObserver.NavigationChangedListener, OnMediaUnmounted {

    public enum DecompressType {
        DECOMPRESS,
        DECOMPRESS_CURRENT_FOLDER,
        DECOMPRESS_FROM_PREVIEW
    }

    private static HashSet<Integer> sWorkingSet;
    private DecompressType mDecompressType;
    private Context mContext;
    private int mProcessId;
    private AbsMyFilesFragment mFragment;
    private ArrayList<FileRecord> mRecordList;
    private FileRecord mDstRecord;
    private ArrayList<FileRecord> mTargetRecordList;
    private EditTextDialogFragment mEditDialog;
    protected ListenerMgr mListenerMgr;

    @SuppressWarnings("unchecked")
    @Override
    public void execute(INotification notification) {
        if (sWorkingSet == null) {
            sWorkingSet = new HashSet<>();
        }
        Object[] params = (Object[]) notification.getBody();
        mDecompressType = (DecompressType) params[0];
        mContext = (Context) params[1];
        mProcessId = (Integer) params[2];
        mFragment = (AbsMyFilesFragment) params[3];
        mListenerMgr = new ListenerMgr();
        mListenerMgr.addListener(new SystemBroadcastReceiver(mContext, this, ListenerMgr.LifeCycle.CREATE, ListenerMgr.LifeCycle.DESTROY));
        mListenerMgr.notifyCreate();

        if (!sWorkingSet.contains(mProcessId)) {
            Log.d(this, "add working set : " + mProcessId);
            sWorkingSet.add(mProcessId);
            switch (mDecompressType) {
                case DECOMPRESS:
                case DECOMPRESS_CURRENT_FOLDER:
                    mRecordList = (ArrayList<FileRecord>) params[4];
                    break;
                case DECOMPRESS_FROM_PREVIEW:
                    mRecordList = new ArrayList<>();
                    FileRecord archiveRecord = (FileRecord) params[4];
                    mRecordList.add(archiveRecord);
                    mTargetRecordList = (ArrayList<FileRecord>) params[5];
                    break;
            }

            // if fragment is null, enter the folder that has archive file.
            // (execute compress file from external)
            if (mFragment == null) {
                NavigationInfo info = NavigationInfo.getInstance(NavigationInfo.NavigationMode.Normal, mRecordList.get(0).getParent());
                NavigationManager nm = NavigationManager.getInstance(mProcessId);
                nm.registerNavigationChangedListener(this);
                nm.enter(info);
            } else {
                doDecompress();
            }
        } else {
            Log.d(this, "already working : " + mProcessId);
        }
    }

    private void doDecompress() {
        Log.d(this, "start decompress : " + mDecompressType);
        switch (mDecompressType) {
            case DECOMPRESS:
                String defaultFolderName;
                NavigationInfo info = mFragment.getNavigationInfo();
                mDstRecord = info.getCurRecord();
                if (mRecordList.size() == 1) {
                    defaultFolderName = mRecordList.get(0).getNameWithoutExt();
                    if (defaultFolderName.length() > AppConstants.MAX_INPUT_LENGTH) {
                        defaultFolderName = defaultFolderName.substring(0, AppConstants.MAX_INPUT_LENGTH);
                    }
                } else {
                    defaultFolderName = mContext.getString(R.string.new_folder);
                }
                mEditDialog = new EditTextDialogFragment.Builder()
                        .setEditTextCallback(this)
                        .setTitle(R.string.menu_unzip_title)
                        .setOkText(R.string.menu_unzip)
                        .setDefaultText(defaultFolderName)
                        .build();
                mEditDialog.show(mFragment.getFragmentManager());
                break;

            case DECOMPRESS_CURRENT_FOLDER:
                info = NavigationManager.getInstance(mFragment.getProcessId()).getCurInfo();
                if (info != null) {
                    mDstRecord = info.getCurRecord();
                    decompressRecord();
                }
                break;

            case DECOMPRESS_FROM_PREVIEW:
                info = mFragment.getNavigationInfo();
                FileRecord curRecord = info.getCurRecord();
                if (curRecord.getStorageType() == FileRecord.StorageType.Compress) {
                    FileRecord archive = ((CompressFileRecord) curRecord).getArchiveRecord();
                    FileRecord parent = archive.getParent();
                    if (parent != null) {
                        String dstPath = parent.getFullPath() + "/" + archive.getNameWithoutExt();
                        mDstRecord = FileRecord.createFileRecord(parent.getStorageType(), dstPath);
                        decompressRecord();
                    }
                }
                break;
        }
    }

    @Override
    public boolean checkNameExist(String inputString) {
        return false;
    }

    @Override
    public boolean checkText(String inputString, Activity activity) {
        return true;
    }

    @Override
    public void onOK(String inputString, Activity activity) {
        mListenerMgr.notifyDestroy();

        if (checkText(inputString, activity)) {
            mEditDialog.onFinished(true, null, null);
            String renamePath = mDstRecord.getFullPath() + "/" + inputString;
            mDstRecord = FileRecord.createFileRecord(mDstRecord.getStorageType(), renamePath);
            decompressRecord();
        }
        SamsungAnalyticsLog.sendLog(SamsungAnalyticsLog.ScreenPath.UNZIP_POPUP, SamsungAnalyticsLog.Event.UNZIP, null);
    }

    @Override
    public void onCancel(Activity activity) {
        finishCmd();
        SamsungAnalyticsLog.sendLog(SamsungAnalyticsLog.ScreenPath.UNZIP_POPUP, SamsungAnalyticsLog.Event.CANCEL, null);
    }

    @Override
    public void onResult(FileOperator.Operation opType, boolean bRet, Bundle extras) {
        Log.d(this, "result : " + opType + ", " + bRet);
        if (mDecompressType == DecompressType.DECOMPRESS_FROM_PREVIEW && mFragment != null) {
            NavigationManager naviMgr = NavigationManager.getInstance(mFragment.getProcessId());
            if (bRet) {
                if (extras != null) {
                    String dstPath = extras.getString(AbsCompressorImp.FINAL_DST_PATH);
                    if (dstPath != null) {
                        mDstRecord = FileRecord.createFileRecord(mDstRecord.getStorageType(), dstPath);
                    }
                }
                NavigationInfo info = NavigationInfo.getInstance(NavigationInfo.NavigationMode.Normal, mDstRecord);
                naviMgr.leaveWithEnter(info);
            } else {
                if (naviMgr.getDepth() > 1) {
                    NavigationInfo info = naviMgr.getCurInfo();
                    if (info != null && info.getStorageType() != FileRecord.StorageType.Home) {
                        naviMgr.leave(mContext);
                    }
                } else {
                    if (mFragment.getActivity() != null) {
                        mFragment.getActivity().finish();
                    }
                }
            }
        }
        finishCmd();
    }

    private void decompressRecord() {
        Log.d(this, String.format(Locale.getDefault(), "decompress : [%d][%s]", mProcessId, mDecompressType.toString()));
        mFragment.finishActionMode();
        FileOperationArgs args = new FileOperationArgs();
        args.mDecompressType = mDecompressType;
        args.mSrcList = mRecordList;
        args.mDst = mDstRecord;
        if (mDecompressType == DecompressType.DECOMPRESS_FROM_PREVIEW) {
            args.mDecompressTargetList = mTargetRecordList;
        }
        FileOperationFragment fg = FileOperationFragment.createInstance(mContext, mFragment, mFragment.getFragmentManager(),
                FileOperator.Operation.DECOMPRESS, args, this);
        fg.show();
    }

    @Override
    public void onNavigationChanged(NavigationInfo preInfo, NavigationInfo curInfo) {
        mFragment = curInfo.getCurFragment();
        if (mFragment != null) {
            NavigationManager.getInstance(mFragment.getProcessId()).unregisterNavigationChangedListener(this);
            doDecompress();
        } else {
            Log.e(this, "curren fragment is null");
        }
    }

    @Override
    public void onMediaUnmounted(String path) {
        Log.d(this, "onMediaUnmounted : " + path);
        if (FileUtils.isPrivateFolder(mDstRecord.getFullPath())) {
            if (mEditDialog != null && mEditDialog.getDialog() != null) {
                mEditDialog.getDialog().cancel();
                finishCmd();
            }
            mListenerMgr.notifyDestroy();
        }
    }

    private void finishCmd() {
        Log.d(this, "finish decompress : " + mProcessId);
        sWorkingSet.remove(mProcessId);
    }
}
